package it.alsoft.dojomanager.be.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class GenericDaoImpl<ID extends Serializable, T extends Serializable>
		implements

		GenericDao<ID, T> {

	private static final Logger log = LoggerFactory
			.getLogger(GenericDaoImpl.class);

	private Class<T> valueClass;

	@SuppressWarnings("unchecked")
	public GenericDaoImpl() {
		this.valueClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
	}

	public void delete(T target) {
		log.debug("{} - delete - {}", valueClass.getName(), target);
		getEntityManager().remove(target);
	}

	public T findByID(ID id) {
		T found = getEntityManager().find(valueClass, id);
		if (log.isDebugEnabled())
			log.debug(valueClass.getName() + " - findById - [" + id + "] -> [" + found + "]");
		return found;
	}

	public void persist(T target) {
		getEntityManager().persist(target);
		log.debug("{} - persist - {}", valueClass.getName(), target);
	}

	public T merge(T target) {
		T merged = getEntityManager().merge(target);
		log.debug("{} - merge - {}", valueClass.getName(), merged);
		return merged;
	}

	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		String queryString = "FROM " + valueClass.getSimpleName();
		List<T> results = getEntityManager().createQuery(queryString).getResultList();
		log.debug("{} - findAll() - result count: {}", valueClass.getName(),results.size());
		return results;

	}

	public void deleteAll() {
		String queryString = "DELETE FROM " + valueClass.getSimpleName();
		Query query = getEntityManager().createQuery(queryString);
		int c = query.executeUpdate();
		log.debug("{} - deleteAll() - update result: {}", valueClass.getName(), c);
	}

	public void flush() {
		getEntityManager().flush();
	}

	@PostConstruct
	protected void hasEntityManager() {
		if (getEntityManager() == null) {
			throw new RuntimeException("No entity manager on DAO [" + this.getClass().getName() + "]");
		}
	}

	protected abstract EntityManager getEntityManager();

}